#pragma once
#include "Channel.hpp"

namespace ouyangmq
{
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;
        Connection(const muduo::net::TcpConnectionPtr &conn,
                   const ProtobufCodecPtr &codec, const ConsumerManager::ptr &cmp,
                   const VirtualHost::ptr &vhp, const threadpool::ptr &pool)
            : _conn(conn), _codec(codec), _cmp(cmp), _vhp(vhp), _pool(pool), _channels(std::make_shared<ChannelManager>())
        {
        }

        // 打开一个信道
        void openChannel(const openChannelRequestPtr &req)
        {
            // 1.判断信道ID是否重复
            // 2.创建信道
            // 3.给客户端回复
            bool ret = _channels->openChannel(req->rid(), _conn, _codec, _cmp, _vhp, _pool);
            if (ret == false)
            {
                return basicResponse(false, req->rid(), req->cid());
            }
            return basicResponse(true, req->rid(), req->cid());
        }

        // 关闭一个信道
        void closeChannel(const closeChannelRequestPtr &req)
        {
            _channels->closeChannel(req->cid());
            return basicResponse(true, req->rid(), req->cid());
        }

        Channel::ptr getChannel(const std::string &cid)
        {
            return _channels->GetOneChannel(cid);
        }

    private:
        // 响应函数
        void basicResponse(bool ok, const std::string &rid, const std::string &cid)
        {
            // 响应
            basicCommonResponse resp;
            resp.set_rid(rid);
            resp.set_cid(cid);
            resp.set_ok(ok);
            // 发送
            _codec->send(_conn, resp);
        }

    private:
        // 1. 信道关联的连接
        muduo::net::TcpConnectionPtr _conn;
        // 2. protobuf协议处理句柄
        ProtobufCodecPtr _codec;
        // 3. 消费者管理句柄
        ConsumerManager::ptr _cmp;
        // 4. 虚拟机句柄
        VirtualHost::ptr _vhp;
        // 5. 工作线程池
        threadpool::ptr _pool;
        // 6. 信道管理句柄
        ChannelManager::ptr _channels;
    };

    class ConnectionManager
    {
    public:
        using ptr = std::shared_ptr<ConnectionManager>;
        ConnectionManager()
        {
            LogModule::LOG(LogModule::LogLevel::INFO) << "new ConnectionManager";
        }

        // 创建连接
        void newConnection(const muduo::net::TcpConnectionPtr &conn,
                           const ProtobufCodecPtr &codec, const ConsumerManager::ptr &cmp,
                           const VirtualHost::ptr &vhp, const threadpool::ptr &pool)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _connect_manger.find(conn);
            if (it != _connect_manger.end())
            {
                return;
            }
            auto self_conn = std::make_shared<Connection>(conn, codec, cmp, vhp, pool);
            _connect_manger.emplace(conn, self_conn);
        }

        // 删除连接
        void delConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _connect_manger.erase(conn);
        }

        // 获取连接
        Connection::ptr getConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _connect_manger.find(conn);
            if (it == _connect_manger.end())
            {
                return Connection::ptr();
            }
            return it->second;
        }

    private:
        std::mutex _mutex;
        std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _connect_manger;
    };
}